package com.ly.aidlpratice.aidl

import android.app.Service
import android.content.Intent
import android.os.IBinder
import android.os.Process
import android.os.RemoteCallbackList
import com.ly.aidlpratice.IBookCallback
import com.ly.aidlpratice.IBookInterface
import com.ly.aidlpratice.bean.Book
import com.ly.aidlpratice.util.logDebug
import com.ly.aidlpratice.util.logError
import java.lang.Exception
import kotlin.collections.Map as Map

class AIDLService : Service() {

    private val mTag: String by lazy { this::class.java.simpleName }

    private val mAIDLInterface = AIDLInterface()

    private val mBookList by lazy {
        val list = ArrayList<Book>()
        list.add(Book("Web从入门到精通", 3000, 40f))
        list
    }

    private val mBookMap by lazy {
        val map = HashMap<Int, Book>()
        map[3000] = Book("Web从入门到精通", 3000, 54f)
        map
    }

    override fun onBind(intent: Intent): IBinder {
        logDebug(mTag, "onBind $intent")
        return mAIDLInterface.asBinder()
    }

    override fun onUnbind(intent: Intent?): Boolean {
        logDebug(mTag, "onUnbind ${intent?.toString() ?: ""}")
        return super.onUnbind(intent)
    }

    override fun onDestroy() {
        super.onDestroy()
        logDebug(mTag, "onDestroy")
        Process.killProcess(Process.myPid())
    }

    /**
     * 服务端的方法执行是在Binder线程池里面，所以当有多个客户端调用方法的时候，需要考虑线程安全的问题。
     *
     * 下面的方法中都加上了锁，仅仅是为练习，并没有仔细考虑是否需要加锁。
     */
    private inner class AIDLInterface : IBookInterface.Stub() {

        private val mIBookCallbackList: RemoteCallbackList<IBookCallback> =
            RemoteCallbackList<IBookCallback>()

        override fun getBook(): Book {
            synchronized(this) {
                printThreadLog("getBook")
                return mBookList[0]
            }
        }

        override fun getAllBook(): MutableList<Book> {
            synchronized(this) {
                printThreadLog("getAllBook")
                return mBookList
            }
        }

        override fun isContainBook(name: String?): Boolean {
            synchronized(this) {
                printThreadLog("isContainBook")
                ///此处线程睡眠8s，这种情况，客户端在主线程调用该方法，就会出现掉帧情况
                Thread.sleep(8000L)
                if (name == null) return false

                for (book in mBookList) {
                    if (book.name.equals(name))
                        return true
                }

                return false
            }
        }

        override fun updateBookPrice(code: Int, price: Float) {
            synchronized(this) {
                printThreadLog("updateBookPrice")
                val book = mBookMap[code]
                book?.also {
                    it.price = price
                    callback(it)
                }
            }
        }

        override fun getBookPrice(code: Int): Float {
            synchronized(this) {
                printThreadLog("getBookPrice")
                ///此处线程睡眠8s，这种情况，客户端在主线程调用该方法，就会出现掉帧情况
                Thread.sleep(8000L)
                val book = mBookMap[code]
                book?.also {
                    return it.price
                }

                return -1f
            }
        }

        override fun insertBook(book: Book?) {
            synchronized(this) {
                printThreadLog("insertBook")
                book?.also { mBookList.add(it) }
            }
        }

        override fun insertBookList(list: MutableList<Book>?) {
            synchronized(this) {
                printThreadLog("insertBookList")
                list?.also { mBookList.addAll(it) }
            }
        }

        override fun getBookMap(): HashMap<Int, Book> {
            synchronized(this) {
                printThreadLog("getBookMap")
                return mBookMap
            }
        }

        override fun insertBookMapIn(map: MutableMap<Any?, Any?>?): HashMap<Int, Book> {
            synchronized(this) {
                printThreadLog("insertBookMapIn")
                map?.also {
                    mBookMap.putAll(it as Map<Int, Book>)
                }
                return mBookMap
            }
        }

        override fun insertBookMapOut(map: MutableMap<Any?, Any?>?): HashMap<Int, Book> {
            synchronized(this) {
                printThreadLog("insertBookMapOut")
                map?.also {
                    mBookMap.putAll(it as Map<Int, Book>)
                }
                return mBookMap
            }
        }

        override fun insertBookMapInout(map: MutableMap<Any?, Any?>?): HashMap<Int, Book> {
            synchronized(this) {
                printThreadLog("insertBookMapInout")
                map?.also {
                    mBookMap.putAll(it as Map<Int, Book>)
                }
                return mBookMap
            }
        }

        override fun registerCallback(callback: IBookCallback?) {
            callback?.also {
                val result = mIBookCallbackList.register(it)
                printThreadLog("registerCallback", msg = if (result) "success" else "fail")
            }
        }

        override fun unregisterCallback(callback: IBookCallback?) {
            callback?.also {
                val result = mIBookCallbackList.unregister(it)
                printThreadLog("unregisterCallback", msg = if (result) "success" else "fail")
            }
        }

        private fun callback(book: Book) {
            val length = mIBookCallbackList.beginBroadcast()
            for (i in 0 until length) {
                try {
                    mIBookCallbackList.getBroadcastItem(i).callback(book)
                } catch (e: Exception) {
                    logError(mTag, e)
                }
            }
            mIBookCallbackList.finishBroadcast()
        }

        private fun printThreadLog(funcName: String, msg: String = "") {
            logDebug(mTag, "[$funcName][thread.name=${Thread.currentThread().name}]")
        }
    }
}